package com.zxy.config;

import cn.echo.model.LocalUser;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled= true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http     //禁用csrf 关闭跨站请求伪造保护 ,在过滤器链条中移除csrfFilter
                .csrf().disable()
                //不再创建 httpSession
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //认证不通过，统一返回格式
                .and().exceptionHandling().authenticationEntryPoint((request,  response, authException)->{
                    //设置返回编码格式，解决中文乱码
                    response.setContentType("application/json;charset=utf-8");
                    Dict dict = Dict.create().set("code", 401).set("message", "没有足够的权限访问资源");
                    response.getWriter().write(JSONUtil.toJsonStr(dict));
                })
                .and()
                //权限验证
                .authorizeRequests()
                //登录和注册接口 允许匿名访问
                .antMatchers("/api/user/register","/api/user/login").anonymous()
                .antMatchers("/webjars/**","/swagger-*/**","/v2/**").permitAll()
                //除上面之外，所有接口都需要认证
                .anyRequest().authenticated()
                .and()
                .addFilter(new TokenAuthFilter(authenticationManager()));

    }


    static class TokenAuthFilter extends BasicAuthenticationFilter {

        public TokenAuthFilter(AuthenticationManager authenticationManager) {
            super(authenticationManager);
        }

        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

            String token = request.getHeader("token");
            if(!ObjUtil.isEmpty(token)){
                //从token中解析出来 用户信息
                JWTPayload payload = JWTUtil.parseToken(token).getPayload();
                LocalUser localUser = JSONUtil.toBean(payload.toString(), LocalUser.class);
                String[] roles = localUser.getRoles();

                List<SimpleGrantedAuthority> authorities = new ArrayList<>();

                for (String role : roles){
                    //必须加，不加的通过注解验证就不通过， @PreAuthorize可以不加，但这里必须要加
                    authorities.add(new SimpleGrantedAuthority("ROLE_"+role));
                }

                UsernamePasswordAuthenticationToken authenticationToken
                        = new UsernamePasswordAuthenticationToken(localUser.getId(),token,authorities);
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }

            chain.doFilter(request,response);

        }
    }
}
